#ifndef SGU_CONIC2D_H
#define SGU_CONIC2D_H

SGU_NS_BEGIN

class Circle2D : public Serializable
{
	DECLARE_SERIALIZABLE(Circle2D)

	private:
	Point2D _p;
	real _r;
	
	public:
	Circle2D() : _r(real_NaN()) {}
	Circle2D(const Point2D & p, real r) : _p(p), _r(r) {}
	static const Circle2D U;
	
	const Point2D & center() const {return _p;}
	real radius() const {return _r;}
 
	bool co(const Point2D & p) const {return dist2(p,_p) < sqr(_r);}

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};


class Arc2D : public Serializable
{
	DECLARE_SERIALIZABLE(Arc2D)
	
	private:
	Circle2D _c;
	real _a,_b;


	public:

	Arc2D() : _a(real_NaN()), _b(real_NaN()) {}
	Arc2D(const Circle2D & c, real a, real b) : _c(c), _a(angle_Pi_Pi(a)), _b(angle_Pi_Pi(b)) {}
	Arc2D(const Point2D & p, real r, real a, real b) : _c(p,r), _a(angle_Pi_Pi(a)), _b(angle_Pi_Pi(b)) {}

	const Circle2D & circle() const {return _c;}
	real a() const {return _a;}
	real b() const {return _b;}

	real length() const {return (_b - _a) * _c.radius();}
	const Point2D pointA() const;
	const Point2D pointB() const;

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);

};


class Ellipse2D : public Serializable
{
	DECLARE_SERIALIZABLE(Ellipse2D)
	
	private:
	Transform2D _t;


	public:

	Ellipse2D() {}
	Ellipse2D(const Circle2D & c) : _t(Matrix22(c.radius(),0,0,c.radius()),Vector2D(c.center())) {}
	Ellipse2D(const Transform2D & t) : _t(t) {}

	const Transform2D & t() const {return _t;}

	const Point2D center() const {return Point2D(_t.vector());}
	const Vector2D axis() const;
	const real ratio() const;

	bool co(const Point2D & p) {return !(Vector2D(p*~_t))<1;}

	Ellipse2D & operator *= (const Transform2D &);
	const Ellipse2D operator * (const Transform2D & t) const {return Ellipse2D(_t * t);}
	
	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);
};


class EllipticArc2D : public Serializable
{
	DECLARE_SERIALIZABLE(EllipticArc2D)
	
	private:
	Ellipse2D _e;
	real _a,_b; // angoli dell'arco di circonferenza unitaria


	public:

	EllipticArc2D() : _a(real_NaN()), _b(real_NaN()) {}
	EllipticArc2D(const Arc2D & k) : _e(k.circle()), _a(k.a()), _b(k.b()) {}

	real a() const {return _a;}
	real b() const {return _b;}
	const Ellipse2D & ellipse() const {return _e;}

	EllipticArc2D & operator *= (const Transform2D &);
	const EllipticArc2D operator * (const Transform2D &) const;

	const Point2D pointA() const {return Point2D(Vector2D::polar(1,_a))*_e.t();}
	const Point2D pointB() const {return Point2D(Vector2D::polar(1,_b))*_e.t();}

	void serialize(BOStorage &) const;
	void serialize(BIStorage &);
	void serialize(TOStorage &) const;
	void serialize(TIStorage &);

};


std::pair<Point2D,Point2D> inters(const Circle2D & c, const Line2D & r);
std::pair<Point2D,Point2D> inters(const Circle2D & c, const Segment2D & r);
std::pair<Point2D,Point2D> inters(const Arc2D & a, const SemiLine2D & r);
std::pair<Point2D,Point2D> inters(const Arc2D & arc, const Segment2D & seg);

std::pair<Point2D,Point2D> inters(const Ellipse2D & c, const Line2D & r);
std::pair<Point2D,Point2D> inters(const Ellipse2D & c, const SemiLine2D & r);
std::pair<Point2D,Point2D> inters(const Ellipse2D & c, const Segment2D & r);

std::pair<Point2D,Point2D> inters(const EllipticArc2D & c, const Line2D & r);
std::pair<Point2D,Point2D> inters(const EllipticArc2D & c, const SemiLine2D & r);
std::pair<Point2D,Point2D> inters(const EllipticArc2D & c, const Segment2D & r);


std::pair<Point2D,Point2D> inters(const Circle2D &, const Circle2D &);
std::pair<Point2D,Point2D> inters(const Arc2D &, const Arc2D &);

real dist2(const Point2D & p, const Circle2D & c);
inline real dist(const Point2D & p, const Circle2D & c) {return ::sqrt(dist2(p,c));}

real dist2(const Point2D & p, const Arc2D & a);
inline real dist(const Point2D & p, const Arc2D & a) {return ::sqrt(dist2(p,a));}

SGU_NS_END

#endif
